/* -*- Mode: java; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
 */

import org.apache.xerces.xni.Augmentations;
import org.apache.xerces.xni.QName;
import org.apache.xerces.xni.XMLAttributes;
import org.apache.xerces.xni.XMLLocator;
import org.apache.xerces.xni.XMLString;
import org.apache.xerces.xni.XNIException;
import org.apache.xerces.xni.parser.XMLDocumentFilter;
import org.apache.xerces.xni.parser.XMLInputSource;
import org.apache.xerces.parsers.DOMParser;//ZJC
import org.cyberneko.html.HTMLConfiguration;
import org.cyberneko.html.filters.DefaultFilter;
import org.cyberneko.html.filters.Identity;
import org.cyberneko.html.filters.Writer;

/**
 * JHoneyC client
 *
 * @author Zhijie Chen
 * @author Chengyu Song
 *
 * @version $Id: JHoneyClient.java,v 0.0.1 2009/04/30 22:04 Exp $
 */
public class JHoneyClient
    extends DefaultFilter {

    //
    // Constants
    //

    /** Augmentations feature identifier. */
    protected static final String AUGMENTATIONS = "http://cyberneko.org/html/features/augmentations";

    /** Filters property identifier. */
    protected static final String FILTERS = "http://cyberneko.org/html/properties/filters";

    /** Document class identifier. */
    protected static final String DOCUMENT_CLASS_NAME = "http://apache.org/xml/properties/dom/document-class-name";

    /** Script type ("text/x-nekoscript"). */
    protected static final String SCRIPT_TYPE = "javascript";

    //
    // Data
    //

    /** The NekoHTML configuration. */
    protected DOMParser fConfiguration;

    /** A string buffer to collect the "script". */
    protected StringBuffer fBuffer;
    
    /** The system identifier of the source document. */
    protected String fSystemId;

    /** The script count. */
    protected int fScriptCount;

    protected HoneyJS jsvm;
    
    //
    // Constructors
    //

    /** Constructs a script object with the specified configuration. */
    public JHoneyClient(DOMParser config,HoneyJS ajsvm) {
        fConfiguration = config;
        jsvm = ajsvm;
    } // <init>(HTMLConfiguration)

    //
    // XMLDocumentHandler methods
    //

    /** Start document. */
    public void startDocument(XMLLocator locator, String encoding, Augmentations augs) 
        throws XNIException {
        fBuffer = null;
        fSystemId = locator != null ? locator.getLiteralSystemId() : null;
        fScriptCount = 0;
        super.startDocument(locator, encoding, augs);
    } // startDocument(XMLLocator,String,Augmentations)

    /** Start element. */
    public void startElement(QName element, XMLAttributes attrs, Augmentations augs)
        throws XNIException {
        if (element.rawname.equalsIgnoreCase("script")) {
            String value = attrs.getValue("type");
            if (value == null || value.indexOf(SCRIPT_TYPE) != -1) {
                fBuffer = new StringBuffer();
                return;
            }
        }
        super.startElement(element, attrs, augs);
    } // startElement(QName,XMLAttributes,Augmentations)

    /** Empty element. */
    public void emptyElement(QName element, XMLAttributes attrs, Augmentations augs)
        throws XNIException {
        if (element.rawname.equalsIgnoreCase("script") && attrs != null) {
            String value = attrs.getValue("type");
            if (value != null && value.equalsIgnoreCase(SCRIPT_TYPE)) {
                return;
            }
        }
        super.emptyElement(element, attrs, augs);
    } // emptyElement(QName,XMLAttributes,Augmentations)

    /** Characters. */
    public void characters(XMLString text, Augmentations augs)
        throws XNIException {
        if (fBuffer != null) {
            fBuffer.append(text.ch, text.offset, text.length);
        }
        else {
            super.characters(text, augs);
        }
    } // characters(XMLString,Augmentations)

    /** End element. */
    public void endElement(QName element, Augmentations augs) throws XNIException {
        if (fBuffer != null) {
            try {
                // run "script" and generate HTML output
                //StringWriter sout = new StringWriter();
                //PrintWriter out = new PrintWriter(sout);
            	if(fScriptCount == 0){
            		jsvm.initializeDocument(fConfiguration.getDocument());
            	}
            	fScriptCount++;
                String buffer = fBuffer.toString();
                fBuffer = null;
                jsvm.evaluateBuffer(buffer);

                // push new input source
                //String systemId = fSystemId != null ? fSystemId+'_' : "";
                //systemId += "script"+fScriptCount;
                //XMLInputSource source = new XMLInputSource(null, systemId, null,
                                                          // new StringReader(sout.toString()),
                                                           //"UTF-8");
                //fConfiguration.pushInputSource(source);
            }
            finally {
                fBuffer = null;
            }
        }
        else {
            super.endElement(element, augs);
        }
    } // endElement(QName,Augmentations)

    //
    // MAIN
    //

    /** Main. */
    public static void main(String[] argv) throws Exception {
    	HTMLConfiguration HtmlConf = new HTMLConfiguration();
    	GlobalEnvironment.HtmlConf = HtmlConf;
        DOMParser parser = new DOMParser(HtmlConf);
        GlobalEnvironment.parser = parser;
        parser.setProperty(DOCUMENT_CLASS_NAME, "HoneyDocument");
        HoneyJS jsvm = new HoneyJS(parser);
        parser.setFeature(AUGMENTATIONS, true);
        XMLDocumentFilter[] filters = { new JHoneyClient(parser,jsvm), new Identity(), new Writer() };
        parser.setProperty(FILTERS, filters);
        for (int i = 0; i < argv.length; i++) {
            parser.parse(new XMLInputSource(null, argv[i], null));
        }
    } // main(String[])

} // class Script
